package ai.people.platform.archives.service.impl;

import ai.people.netmon.framework.domain.gang.construction.entity.*;
import ai.people.netmon.framework.domain.gang.construction.request.*;
import ai.people.netmon.framework.domain.gang.construction.vo.LabelLibTreeVO;
import ai.people.netmon.framework.exception.enums.CommonEnum;
import ai.people.netmon.framework.exception.enums.FileExceptionEnum;
import ai.people.netmon.framework.exception.enums.LabelLibExceptionEnum;
import ai.people.netmon.framework.exception.type.BusinessException;
import ai.people.netmon.framework.model.response.PageResponse;
import ai.people.netmon.framework.utils.AssertUtils;
import ai.people.netmon.utils.ExcelUtils;
import ai.people.platform.archives.mapper.LabelLibMapper;
import ai.people.platform.archives.service.*;
import ai.people.platform.archives.service.listener.LabelLibAccountExcelListener;
import ai.people.platform.archives.service.listener.LabelLibSampleExcelListener;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author zhenglin
 * @since 2022-07-19
 */
@Service
@Slf4j
public class LabelLibServiceImpl extends ServiceImpl<LabelLibMapper, LabelLib> implements LabelLibService {

    @Autowired
    LabelLibAccountService labelLibAccountService;
    @Autowired
    LabelLibAccountRecommendService labelLibAccountRecommendService;
    @Autowired
    LabelLibKeywordService labelLibKeywordService;
    @Autowired
    LabelLibKeywordRecommendService labelLibKeywordRecommendService;
    @Autowired
    LabelLibSampleService labelLibSampleService;
    @Autowired
    LabelLibSampleRecommendService labelLibSampleRecommendService;

    /**
     * 添加标签
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addLabel(LabelLibSaveOrUpdateRequest request) {
        LabelLib labelLib = new LabelLib(request);
        String labelName = labelLib.getLabelName();
        checkName(labelName);
        boolean save = save(labelLib);
        AssertUtils.isTrue(save, CommonEnum.FAIL);
        //新增一条该标签的关键词数据
        LabelLibKeyword labelLibKeyword = new LabelLibKeyword();
        labelLibKeyword.setLabelLibId(labelLib.getId());
        boolean keywordFlag = labelLibKeywordService.save(labelLibKeyword);
        AssertUtils.isTrue(keywordFlag, CommonEnum.FAIL);
    }

    private void checkName(String labelName) {
        long count = count(new LambdaQueryWrapper<LabelLib>().eq(LabelLib::getLabelName, labelName));
        if (count > 0) {
            throw new BusinessException(LabelLibExceptionEnum.LABEL_LIB_EXIST);
        }
    }

    /**
     * 更新标签
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLabel(LabelLibSaveOrUpdateRequest request) {
        LabelLib labelLib = new LabelLib(request);
        checkName(labelLib.getLabelName());
        labelLib.setId(request.getId());
        labelLib.setUpdateTime(new Date());
        boolean update = updateById(labelLib);
        AssertUtils.isTrue(update, CommonEnum.FAIL);
    }

    /**
     * 删除标签
     *
     * @param id id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteLabel(Long id) {
        boolean remove = removeById(id);
        AssertUtils.isTrue(remove, CommonEnum.FAIL);
        List<LabelLib> list = list(new LambdaQueryWrapper<LabelLib>().eq(LabelLib::getParentId, id));
        for (LabelLib labelLib : list) {
            deleteLabel(labelLib.getId());
        }
    }

    /**
     * 列表标签树
     *
     * @return {@link List}<{@link LabelLibTreeVO}>
     */
    @Override
    public List<LabelLibTreeVO> listLabelTree() {
        List<LabelLibTreeVO> result = new ArrayList<>();

        List<LabelLib> list = list();
        Map<Long, List<LabelLib>> mapping = list.stream().collect(Collectors.groupingBy(LabelLib::getParentId));

        //递归构造树
        List<LabelLib> labelLibs = mapping.get(0L);
        for (LabelLib root : labelLibs) {
            result.add(buildTree(root, mapping));
        }
        return result;
    }

    private LabelLibTreeVO buildTree(LabelLib root, Map<Long, List<LabelLib>> mapping) {
        LabelLibTreeVO node = new LabelLibTreeVO(root);
        List<LabelLibTreeVO> childrenVo = new ArrayList<>();
        List<LabelLib> children = mapping.get(root.getId());
        if (CollectionUtils.isNotEmpty(children)) {
            for (LabelLib child : children) {
                childrenVo.add(buildTree(child, mapping));
            }
            //递归计算每个父节点的子节点数量
            int sum = childrenVo.stream().mapToInt(LabelLibTreeVO::getChildrenCnt).sum() + childrenVo.size();
            node.setChildrenCnt(sum);
        } else {
            node.setChildrenCnt(0);
        }
        node.setChildren(childrenVo);
        return node;
    }

    /**
     * 点击标签获取账号列表
     *
     * @param request 请求
     * @return {@link PageResponse}<{@link LabelLibAccount}>
     */
    @Override
    public PageResponse<LabelLibAccount> listAccount(LabelLibAccountRequest request) {
        Page<LabelLibAccount> page = new Page<>(request.getOriginPageNo(), request.getPageSize());
        LambdaQueryWrapper<LabelLibAccount> queryWrapper = new LambdaQueryWrapper<LabelLibAccount>()
                .eq(LabelLibAccount::getLabelLibId, request.getLabelLibId()).orderByDesc(LabelLibAccount::getUpdateTime);
        String searchKeywords = request.getSearchKeywords();
        if (StringUtils.isNotBlank(searchKeywords)) {
            queryWrapper.like(LabelLibAccount::getAccount, searchKeywords);
        }
        Page<LabelLibAccount> result = labelLibAccountService.page(page, queryWrapper);
        List<LabelLibAccount> records = result.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageResponse.builderEmpty();
        }
        return PageResponse.builder(records, result.getTotal(), result.getPages(), result.getCurrent());
    }

    /**
     * 账号-添加账号
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addAccount(LabelLibAccountSaveOrUpdateRequest request) {
        LabelLibAccount labelLibAccount = new LabelLibAccount(request);
        long cnt = labelLibAccountService.count(new LambdaQueryWrapper<LabelLibAccount>()
                        .eq(LabelLibAccount::getLabelLibId, labelLibAccount.getLabelLibId())
                        .eq(LabelLibAccount::getPlatform, labelLibAccount.getPlatform())
                .eq(LabelLibAccount::getAccount, labelLibAccount.getAccount()));
        AssertUtils.isTrue(cnt == 0, LabelLibExceptionEnum.LABEL_LIB_ACCOUNT_EXIST);
        boolean save = labelLibAccountService.save(labelLibAccount);
        AssertUtils.isTrue(save, CommonEnum.FAIL);
    }

    /**
     * 账号-上传账号Excel文件
     *
     * @param file       文件
     * @param labelLibId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Integer> uploadAccount(MultipartFile file, Long labelLibId) throws IOException {
        List<Integer> errorLine = new ArrayList<>();
        AssertUtils.isTrue(ExcelUtils.checkSuffix(file.getOriginalFilename()), FileExceptionEnum.FILE_SUFFIX_NOT_SUPPORT);
        log.info("标签库账号导入开始...");
        EasyExcel.read(file.getInputStream(), LabelLibAccountExcel.class, new LabelLibAccountExcelListener(labelLibAccountService,errorLine,labelLibId)).sheet().doRead();
        return errorLine;
    }

    /**
     * 账号-详情
     *
     * @param id id
     * @return {@link LabelLibAccount}
     */
    @Override
    public LabelLibAccount detailAccount(Long id) {
        return labelLibAccountService.getById(id);
    }

    /**
     * 账号-删除账号
     *
     * @param id id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delAccount(Long id) {
        LabelLibAccount byId = labelLibAccountService.getById(id);
        Long recommendId = byId.getRecommendId();
        if (Objects.nonNull(recommendId)){
            boolean update = labelLibAccountRecommendService.update(null, new LambdaUpdateWrapper<LabelLibAccountRecommend>()
                    .eq(LabelLibAccountRecommend::getId, recommendId).set(LabelLibAccountRecommend::getAddFlag, 0));
            AssertUtils.isTrue(update, CommonEnum.FAIL);
        }
        boolean remove = labelLibAccountService.removeById(id);
        AssertUtils.isTrue(remove, CommonEnum.FAIL);
    }

    /**
     * 账号-推荐数据列表
     *
     * @param request 请求
     * @return {@link PageResponse}<{@link LabelLibAccountRecommend}>
     */
    @Override
    public PageResponse<LabelLibAccountRecommend> listLabelAccountRecommend(LabelLibAccountRequest request) {
        Page<LabelLibAccountRecommend> page = new Page<>(request.getOriginPageNo(), request.getPageSize());
        LambdaQueryWrapper<LabelLibAccountRecommend> queryWrapper = new LambdaQueryWrapper<LabelLibAccountRecommend>()
                .eq(LabelLibAccountRecommend::getLabelLibId, request.getLabelLibId())
                .orderByDesc(LabelLibAccountRecommend::getCreateTime);

        Page<LabelLibAccountRecommend> result = labelLibAccountRecommendService.page(page, queryWrapper);
        List<LabelLibAccountRecommend> records = result.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageResponse.builderEmpty();
        }
        return PageResponse.builder(records, result.getTotal(), result.getPages(), result.getCurrent());
    }

    /**
     * 账号-推荐数据添加训练
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void labelAccountRecommendAddToTrain(LabelLibAccountRecommendTrainRequest request) {
        List<Long> ids = request.getIds();
        boolean update = labelLibAccountRecommendService.update(null, new LambdaUpdateWrapper<LabelLibAccountRecommend>().in(LabelLibAccountRecommend::getId, ids).set(LabelLibAccountRecommend::getAddFlag, 1));
        AssertUtils.isTrue(update, CommonEnum.FAIL);

        Long labelLibId = request.getLabelLibId();

        List<LabelLibAccount> saveList = new ArrayList<>();
        List<LabelLibAccountRecommend> list = labelLibAccountRecommendService.list(new LambdaQueryWrapper<LabelLibAccountRecommend>().in(LabelLibAccountRecommend::getId, ids));
        for (LabelLibAccountRecommend labelLibAccountRecommend : list) {
            saveList.add(new LabelLibAccount(labelLibAccountRecommend, labelLibId));
        }
        boolean save = labelLibAccountService.saveBatch(saveList);
        AssertUtils.isTrue(save, CommonEnum.FAIL);
    }

    /**
     * 关键词-获取
     *
     * @param labelLibId 标签自由id
     * @return {@link LabelLibKeyword}
     */
    @Override
    public LabelLibKeyword getKeyword(Long labelLibId) {
        return labelLibKeywordService.getOne(new LambdaQueryWrapper<LabelLibKeyword>().eq(LabelLibKeyword::getLabelLibId, labelLibId));
    }

    /**
     * 关键词-添加关键词
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addKeyword(LabelLibKeywordSaveOrUpdateRequest request) {
        LabelLibKeyword labelLibKeyword = new LabelLibKeyword(request);
        boolean save = labelLibKeywordService.save(labelLibKeyword);
        AssertUtils.isTrue(save, CommonEnum.FAIL);
    }

    /**
     * 更新关键词
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateKeyword(LabelLibKeywordSaveOrUpdateRequest request) {
        LabelLibKeyword labelLibKeyword = new LabelLibKeyword(request);
        labelLibKeyword.setId(request.getId());
        boolean save = labelLibKeywordService.updateById(labelLibKeyword);
        AssertUtils.isTrue(save, CommonEnum.FAIL);
    }

    /**
     * 关键词-删除关键词
     *
     * @param id id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delKeyword(Long id) {
        boolean remove = labelLibKeywordService.removeById(id);
        AssertUtils.isTrue(remove, CommonEnum.FAIL);
    }

    /**
     * 关键词-推荐数据列表
     *
     * @param request 请求
     * @return {@link PageResponse}<{@link LabelLibKeywordRecommend}>
     */
    @Override
    public PageResponse<LabelLibKeywordRecommend> listLabelKeywordRecommend(LabelLibKeywordRequest request) {
        Page<LabelLibKeywordRecommend> page = new Page<>(request.getOriginPageNo(), request.getPageSize());
        LambdaQueryWrapper<LabelLibKeywordRecommend> queryWrapper = new LambdaQueryWrapper<LabelLibKeywordRecommend>()
                .eq(LabelLibKeywordRecommend::getLabelLibId, request.getLabelLibId())
                .orderByDesc(LabelLibKeywordRecommend::getCreateTime);

        Page<LabelLibKeywordRecommend> result = labelLibKeywordRecommendService.page(page, queryWrapper);
        List<LabelLibKeywordRecommend> records = result.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageResponse.builderEmpty();
        }
        return PageResponse.builder(records, result.getTotal(), result.getPages(), result.getCurrent());
    }


    /**
     * 样本集-获取列表
     *
     * @param request 请求
     * @return {@link PageResponse}<{@link LabelLibSample}>
     */
    @Override
    public PageResponse<LabelLibSample> listSample(LabelLibSampleRequest request) {
        Long labelLibId = request.getLabelLibId();
        Page<LabelLibSample> page = new Page<>(request.getOriginPageNo(), request.getPageSize());
        LambdaQueryWrapper<LabelLibSample> queryWrapper = new LambdaQueryWrapper<LabelLibSample>().eq(LabelLibSample::getLabelLibId, labelLibId);
        String searchKeywords = request.getSearchKeywords();
        if (StringUtils.isNotBlank(searchKeywords)) {
            queryWrapper.like(LabelLibSample::getSample, searchKeywords);
        }
        Page<LabelLibSample> result = labelLibSampleService.page(page, queryWrapper);
        List<LabelLibSample> records = result.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageResponse.builderEmpty();
        }
        return PageResponse.builder(records, result.getTotal(), result.getPages(), result.getCurrent());
    }

    /**
     * 样本集-添加样本
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addSample(LabelLibSampleSaveOrUpdateRequest request) {
        LabelLibSample labelLibSample = new LabelLibSample(request);
        boolean save = labelLibSampleService.save(labelLibSample);
        AssertUtils.isTrue(save, CommonEnum.FAIL);
    }

    /**
     * 样本集-上传账号Excel文件
     *
     * @param file       文件
     * @param labelLibId 标签自由id
     * @return {@link List}<{@link Integer}>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Integer> uploadSample(MultipartFile file, Long labelLibId) throws IOException {
        List<Integer> errorLine = new ArrayList<>();
        AssertUtils.isTrue(ExcelUtils.checkSuffix(file.getOriginalFilename()), FileExceptionEnum.FILE_SUFFIX_NOT_SUPPORT);
        log.info("标签库样本集导入开始...");
        EasyExcel.read(file.getInputStream(), LabelLibSampleExcel.class, new LabelLibSampleExcelListener(labelLibSampleService,errorLine,labelLibId)).sheet().doRead();
        return errorLine;
    }

    /**
     * 样本集-删除样本集
     *
     * @param id id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSample(Long id) {
        LabelLibSample byId = labelLibSampleService.getById(id);
        Long recommendId = byId.getRecommendId();
        if (Objects.nonNull(recommendId)){
            boolean update = labelLibSampleRecommendService.update(null, new LambdaUpdateWrapper<LabelLibSampleRecommend>()
                    .eq(LabelLibSampleRecommend::getId, recommendId).set(LabelLibSampleRecommend::getAddFlag, 0));
            AssertUtils.isTrue(update, CommonEnum.FAIL);
        }

        boolean remove = labelLibSampleService.removeById(id);
        AssertUtils.isTrue(remove, CommonEnum.FAIL);
    }

    /**
     * 样本集-推荐数据列表
     *
     * @param request 请求
     * @return {@link PageResponse}<{@link LabelLibSampleRecommend}>
     */
    @Override
    public PageResponse<LabelLibSampleRecommend> listSampleRecommend(LabelLibSampleRequest request) {
        Page<LabelLibSampleRecommend> page = new Page<>(request.getOriginPageNo(), request.getPageSize());
        LambdaQueryWrapper<LabelLibSampleRecommend> queryWrapper = new LambdaQueryWrapper<LabelLibSampleRecommend>().eq(LabelLibSampleRecommend::getLabelLibId, request.getLabelLibId());

        Page<LabelLibSampleRecommend> result = labelLibSampleRecommendService.page(page, queryWrapper);
        List<LabelLibSampleRecommend> records = result.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return PageResponse.builderEmpty();
        }
        return PageResponse.builder(records, result.getTotal(), result.getPages(), result.getCurrent());
    }

    /**
     * 样本集-推荐数据添加训练
     *
     * @param request 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sampleRecommendAddToTrain(LabelLibSampleRecommendTrainRequest request) {
        List<Long> ids = request.getIds();
        boolean update = labelLibSampleRecommendService.update(null, new LambdaUpdateWrapper<LabelLibSampleRecommend>().in(LabelLibSampleRecommend::getId, ids).set(LabelLibSampleRecommend::getAddFlag, 1));
        AssertUtils.isTrue(update, CommonEnum.FAIL);

        Long labelLibId = request.getLabelLibId();

        List<LabelLibSample> saveList = new ArrayList<>();
        List<LabelLibSampleRecommend> list = labelLibSampleRecommendService.list(new LambdaQueryWrapper<LabelLibSampleRecommend>().in(LabelLibSampleRecommend::getId, ids));
        for (LabelLibSampleRecommend data : list) {
            saveList.add(new LabelLibSample(data, labelLibId));
        }
        boolean save = labelLibSampleService.saveBatch(saveList);
        AssertUtils.isTrue(save, CommonEnum.FAIL);

    }


}
